#include "unit_test.h"
#include "SEGGER_RTT.h"
#include "log.h"

#include <stdlib.h>
#include <string.h>

// 接收缓冲区大小
#define UNIT_TEST_BUFFER_SIZE 128
// 接收间隔
#define UNIT_TEST_WAIT_COUNT  5

typedef struct {
    char buffer[UNIT_TEST_BUFFER_SIZE];
    uint16_t read_size;
    uint32_t wait_count;
} unit_test_state_t;

static uint8_t unit_test_check_func_num = 0;
static unit_test_check_function function_table[UNIT_TEST_INSTANCE_MAX_NUM] = {0};

static unit_test_state_t unit_test_state = {0};

/**
 * @brief 字符串转命令
 * 
 * @param buf 字符串缓冲区
 * @param command 输出的命令指针
 * @return 是否有命令
 * @retval 0: 有
 * @retval 1: 没有
 */
static uint8_t unit_test_command_parse(char* buf, unit_test_command_t *command)
{
	uint8_t flag = 1;

	do {
        // 查找'('，以这个的左边作为函数名
		char* param_begin = strchr(buf, '(');
		if (param_begin == NULL) {
            // 没找到，返回
			break;
		}

		*param_begin++ = '\0';
		command->name = buf;
		command->param_count = 0;
		flag = 0;

		while (1) {
			char* param = strchr(param_begin, ',');
			if (param != NULL) {
				// found a param
				*param++ = '\0';
				command->param[command->param_count++] = atoi(param_begin);
				param_begin = param;
			}
			else {
				// not found
				param = strchr(param_begin, ')');
				if (*(param - 1) == '\0' || *(param - 1) == ' ') {
					break;
				}
				else if (param != NULL) {
					param = '\0';
					command->param[command->param_count++] = atoi(param_begin);
				}
				break;
			}

            if (command->param_count >= UNIT_TEST_MAX_PARAM_COUNT)
                break;
		}
	} while (0);

	return flag;
}

/**
 * @brief 匹配命令
 * 
 * @param p_command 命令指针
 */
static void unit_test_lookup_table(unit_test_command_t *p_command)
{
    uint32_t retval;
    unit_test_result_e result;
    uint8_t i;

    for (i=0; i<unit_test_check_func_num; i++) {
        if (function_table[i] != NULL) {
            result = function_table[i](p_command, &retval);
            if (result == UNIT_TEST_RESULT_OK) {
                LOGT("unit_test", "call %s -> void", p_command->name);
                break;
            } else if (result == UNIT_TEST_RESULT_OK_WITH_RETVAL) {
                LOGT("unit_test", "call %s -> %lu", p_command->name, retval);
                break;
            } else if (result == UNIT_TEST_RESULT_INVALID_PARAM_COUNT) {
                LOGT("unit_test", "call %s but invalid param count", p_command->name);
                break;
            }
        }
    }

    if (i >= unit_test_check_func_num) {
        LOGT("unit_test", "%s not match", p_command->name);
    }
}

void unit_test_handler(uint32_t passed_ms)
{
    unit_test_command_t command;

    if (SEGGER_RTT_HasData(0) != 0) {
        unit_test_state.read_size += SEGGER_RTT_Read(0,
            &unit_test_state.buffer[unit_test_state.read_size],
            UNIT_TEST_BUFFER_SIZE - unit_test_state.read_size);
        unit_test_state.wait_count = 0;
    }

    if (unit_test_state.read_size != 0) {
        if (unit_test_state.wait_count < UNIT_TEST_WAIT_COUNT)
            unit_test_state.wait_count += passed_ms;
        if (unit_test_state.wait_count >= UNIT_TEST_WAIT_COUNT) {
            unit_test_state.buffer[unit_test_state.read_size] = '\0';
            if (unit_test_command_parse(unit_test_state.buffer, &command) == 0) {
                unit_test_lookup_table(&command);
            }
            unit_test_state.read_size = 0;
        }
    }
}

uint8_t unit_test_register_check_function(unit_test_check_function function)
{
    if (unit_test_check_func_num >= 8) {
        LOGE("unit_test", "over max check function number");
        return 1;
    }

    if (function == NULL) {
        LOGE("unit_test", "check function is NULL");
        return 1;
    }

    function_table[unit_test_check_func_num++] = function;
    return 0;
}
